/* Copyright (c) 2004-2024 Peigen.info. All rights reserved. */

package info.peigen.hotpot.business.customer.core.repository.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import info.peigen.hotpot.business.account.core.domain.account.Account;
import info.peigen.hotpot.business.account.core.repository.service.AccountRepository;
import info.peigen.hotpot.business.customer.core.domain.Customer;
import info.peigen.hotpot.business.customer.core.domain.CustomerFeeRule;
import info.peigen.hotpot.business.customer.core.domain.CustomerLog;
import info.peigen.hotpot.business.customer.core.domain.action.CustomerCheck;
import info.peigen.hotpot.business.customer.core.domain.action.CustomerConverter;
import info.peigen.hotpot.business.customer.core.domain.operator.CustomerOperator;
import info.peigen.hotpot.business.customer.core.repository.entity.*;
import info.peigen.hotpot.business.customer.core.repository.mapper.CustomerMapper;
import info.peigen.hotpot.business.customer.facade.enums.CustomerLogType;
import info.peigen.hotpot.business.customer.facade.order.log.CustomerLogOrder;
import info.peigen.hotpot.business.fee.core.repository.service.FeeRuleRepository;
import info.peigen.hotpot.common.core.result.ResultCode;
import info.peigen.hotpot.common.service.base.exception.BusinessException;
import info.peigen.hotpot.component.data.repository.beetlsql.entity.AbstractCreateTimeEntity;
import info.peigen.hotpot.component.data.repository.beetlsql.service.AbstractBeetlSqlRepository;
import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.FieldDefaults;
import org.beetl.sql.core.query.LambdaQuery;
import org.beetl.sql.core.query.Query;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.handle.Context;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <b>(CustomerRepository)</b>
 *
 * @author Peigen
 * @version 1.0.0
 * @since 2021/8/2
 */
@SuppressWarnings("unused")
@Data
@EqualsAndHashCode(callSuper = true)
@FieldDefaults(level = AccessLevel.PRIVATE)
@Component
public class CustomerRepository extends AbstractBeetlSqlRepository<CustomerMapper, CustomerEntity> {
    @Inject
    CustomerOperatorRepository               customerOperatorRepository;
    @Inject
    CustomerAuthenticationRepository         customerAuthenticationRepository;
    @Inject
    CustomerAuthenticationBaseRepository     customerAuthenticationBaseRepository;
    @Inject
    CustomerAuthenticationLogRepository      customerAuthenticationLogRepository;
    @Inject
    CustomerAuthenticationIdentityRepository customerAuthenticationIdentityRepository;
    @Inject
    CustomerTechRepository                   customerTechRepository;
    @Inject
    CustomerLogRepository                    customerLogRepository;
    @Inject
    FeeRuleRepository                        feeRuleRepository;
    @Inject
    AccountRepository                        accountRepository;
    @Inject
    PartnerRepository                        partnerRepository;

    public void store(Customer customer) {
        CustomerEntity                             customerEntity                 = CustomerConverter.convertCustomer(customer);
        List<CustomerOperatorEntity>               operatorEntities               = CustomerConverter.convertCustomerOperatorEntities(customer);
        CustomerAuthenticationEntity               authenticationEntity           = CustomerConverter.convertCustomerAuthenticationEntity(customer);
        CustomerAuthenticationBaseEntity           authenticationBaseEntity       = CustomerConverter.convertCustomerAuthenticationBaseEntity(customer);
        List<CustomerAuthenticationIdentityEntity> authenticationIdentityEntities = CustomerConverter.convertAuthenticatorIdentityEntities(customer);
        CustomerTechEntity                         customerTechEntity             = CustomerConverter.convertCustomerTech(customer);
        saveOrUpdate(customerEntity);
        customerOperatorRepository.saveOrUpdateBatch(operatorEntities);
        customerAuthenticationRepository.saveOrUpdate(authenticationEntity);
        customerAuthenticationBaseRepository.saveOrUpdate(authenticationBaseEntity);
        customerAuthenticationIdentityRepository.saveOrUpdateBatch(authenticationIdentityEntities);
        customerTechRepository.saveOrUpdate(customerTechEntity);
        log(customer);
    }

    private void log(Customer customer) {
        log(customer, customer.getMasterOperator().getOperatorId());
    }

    private void log(Customer customer, String operatorId) {
        CustomerLogEntity entity = CustomerLogEntity.builder()
                .customerId(customer.getCustomerId())
                .operatorId(operatorId)
                .type(CustomerLogType.Register)
                .customer(customer)
                .build();
        entity.setPartnerId(customer.getPartnerId());
        customerLogRepository.save(entity);
    }

    public void applyAuthentication(Customer customer) {
        CustomerEntity                             customerEntity                 = CustomerConverter.convertCustomer(customer);
        CustomerAuthenticationEntity               authenticatorEntity            = CustomerConverter.convertCustomerAuthenticationEntity(customer);
        CustomerAuthenticationBaseEntity           authenticatorBaseEntity        = CustomerConverter.convertCustomerAuthenticationBaseEntity(customer);
        List<CustomerAuthenticationIdentityEntity> authenticationIdentityEntities = CustomerConverter.convertAuthenticatorIdentityEntities(customer);

        saveOrUpdate(customerEntity);
        customerAuthenticationRepository.saveOrUpdate(authenticatorEntity);
        customerAuthenticationBaseRepository.saveOrUpdate(authenticatorBaseEntity);
        customerAuthenticationIdentityRepository.getMapper().deleteByCustomerId(customer.getCustomerId());
        customerAuthenticationIdentityRepository.saveOrUpdateBatch(authenticationIdentityEntities);
    }

    public void updateAuthenticationIdentity(Customer customer) {
        List<CustomerAuthenticationIdentityEntity> authenticationIdentityEntities = CustomerConverter.convertAuthenticatorIdentityEntities(customer);
        customerAuthenticationIdentityRepository.getMapper().deleteByCustomerId(customer.getCustomerId());
        customerAuthenticationIdentityRepository.saveOrUpdateBatch(authenticationIdentityEntities);
    }

    public void auditAuthentication(Customer customer) {
        CustomerEntity                        customerEntity            = CustomerConverter.convertCustomer(customer);
        CustomerAuthenticationEntity          authenticatorEntity       = CustomerConverter.convertCustomerAuthenticationEntity(customer);
        List<CustomerAuthenticationLogEntity> authenticationLogEntities = CustomerConverter.convertAuthenticationLogEntities(customer);

        saveOrUpdate(customerEntity);
        customerAuthenticationRepository.saveOrUpdate(authenticatorEntity);
        customerAuthenticationLogRepository.saveOrUpdateBatch(authenticationLogEntities);
    }

    public void updateAuthenticationBaseInfo(Customer customer) {
        CustomerAuthenticationBaseEntity authenticatorBaseEntity = CustomerConverter.convertCustomerAuthenticationBaseEntity(customer);
        customerAuthenticationBaseRepository.saveOrUpdate(authenticatorBaseEntity);
    }

    public void updateControlPeople(Customer customer) {
        List<CustomerAuthenticationIdentityEntity> authenticationIdentityEntities = CustomerConverter.convertAuthenticatorIdentityEntities(customer);
        customerAuthenticationIdentityRepository.getMapper().deleteByCustomerId(customer.getCustomerId());
        customerAuthenticationIdentityRepository.saveOrUpdateBatch(authenticationIdentityEntities);
    }

    public void updateBaseInfo(Customer customer) {
        CustomerEntity customerEntity = CustomerConverter.convertCustomer(customer);
        customerEntity.setUpdateTime(DateUtil.date());
        saveOrUpdate(customerEntity);
    }

    public void updateOperators(Customer customer) {
        List<CustomerOperatorEntity> operatorEntities = CustomerConverter.convertCustomerOperatorEntities(customer);
        customerOperatorRepository.saveOrUpdateBatch(operatorEntities);
    }

    public void deleteCustomerLog(String customerId, CustomerLogType type) {
        customerLogRepository.getMapper().deleteByCustomerId(customerId, type);
    }

    public void updateCustomerLog(CustomerLogOrder customerLogOrder) {
        CustomerLogEntity customerLogEntity = CustomerConverter.convertCustomerLog(customerLogOrder);
        customerLogRepository.saveOrUpdate(customerLogEntity);
    }

    public Customer activeByOpenid(String openid) {
        Assert.notNull(openid, () -> new BusinessException(ResultCode.FAILURE, "openId不得为空!"));

        CustomerTechEntity techEntity = getCustomerTechRepository().getMapper().findByOpenId(openid);
        if (ObjectUtil.isNull(techEntity)) {
            return null;
        }

        CustomerEntity customerEntity = findByCustomerId(techEntity.getCustomerId());
        if (ObjectUtil.isNotEmpty(customerEntity)) {
            return active(customerEntity.getCustomerId());
        }
        return null;
    }

    public Customer active(CustomerEntity customerEntity) {
        String customerId = customerEntity.getCustomerId();
        if (ObjectUtil.isNull(customerEntity)) {
            return null;
        }
        List<CustomerOperatorEntity>               customerOperatorEntities               = customerOperatorRepository.getMapper().createLambdaQuery().andEq(CustomerOperatorEntity::getCustomerId, customerId).select();
        CustomerAuthenticationEntity               customerAuthenticationEntities         = customerAuthenticationRepository.getMapper().createLambdaQuery().andEq(CustomerAuthenticationEntity::getCustomerId, customerId).single();
        CustomerAuthenticationBaseEntity           customerAuthenticationBaseEntities     = customerAuthenticationBaseRepository.getMapper().createLambdaQuery().andEq(CustomerAuthenticationBaseEntity::getCustomerId, customerId).single();
        List<CustomerAuthenticationIdentityEntity> customerAuthenticationIdentityEntities = customerAuthenticationIdentityRepository.getMapper().listByCustomerId(customerId);
        List<CustomerAuthenticationLogEntity>      customerAuthenticationLogEntities      = customerAuthenticationLogRepository.getMapper().listByCustomerId(customerId);
        CustomerTechEntity                         customerTechEntity                     = customerTechRepository.getMapper().findByCustomerId(customerId);
        PartnerEntity                              partnerEntity                          = partnerRepository.getMapper().findByPartnerId(customerTechEntity.getPartnerId());

        Assert.notNull(partnerEntity, () -> new BusinessException(ResultCode.FAILURE, "客户partner激活失败!partnerId=" + customerTechEntity.getPartnerId()));

        Customer customer = CustomerConverter.convertCustomer(customerEntity, customerOperatorEntities, customerAuthenticationEntities,
                customerAuthenticationBaseEntities, customerAuthenticationIdentityEntities, customerAuthenticationLogEntities,
                customerTechEntity, partnerEntity);
        customer.check();
        CustomerCheck.activeCheck(customer);
        // 组装客户账户
        customer.setAccount(activeAccount(customer.getCustomerId()));
        // 手续费规则
        customer.setCustomerFeeRule(findCustomerFeeRule(customer));
        return customer;
    }

    public Customer active(String customerId) {
        CustomerEntity customerEntity = getMapper().findByCustomerId(customerId);
        return active(customerEntity);
    }

    public List<CustomerLog> activeCustomerLog(String customerId, CustomerLogType type, Date date) {
        List<CustomerLogEntity> customerUpdateLogEntities = customerLogRepository.getMapper().createLambdaQuery()
                .andEq(CustomerLogEntity::getCustomerId, customerId)
                .andEq(CustomerLogEntity::getType, type)
                .andGreatEq(CustomerLogEntity::getCreateTime, Query.filterNull(date)).select();

        List<CustomerLog> logs = CustomerConverter.convertCustomerLogList(customerUpdateLogEntities);

        logs.sort((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime()));
        return logs;
    }

    public List<CustomerLog> activeCustomerLogByOperatorId(String operatorId, CustomerLogType type, Date date, int limit) {

        List<CustomerLogEntity> customerUpdateLogEntities = customerLogRepository.getMapper().createLambdaQuery()
                .andEq(CustomerLogEntity::getOperatorId, operatorId)
                .andEq(CustomerLogEntity::getType, type)
                .andGreatEq(CustomerLogEntity::getCreateTime, Query.filterNull(date))
                .desc(CustomerLogEntity::getCreateTime)
                .limit(0, limit).select();

        return CustomerConverter.convertCustomerLogList(customerUpdateLogEntities);
    }

    public CustomerOperator getCustomerOperatorByMobileOrEmail(String operatorLoginName) {
        LambdaQuery<CustomerOperatorEntity> query = customerOperatorRepository.getMapper().createLambdaQuery();
        if (Validator.isMobile(operatorLoginName)) {
            query.andEq(CustomerOperatorEntity::getMobile, operatorLoginName);
        } else if (Validator.isEmail(operatorLoginName)) {
            query.andEq(CustomerOperatorEntity::getEmail, operatorLoginName);
        } else {
            throw new IllegalArgumentException("登录名只支持手机号或邮箱");
        }
        CustomerOperatorEntity operatorEntity = query.single();

        return ObjectUtil.isNull(operatorEntity) ? null : CustomerConverter.convertCustomerOperator(operatorEntity);
    }

    public Customer activeByLoginName(String operatorLoginName) {
        LambdaQuery<CustomerOperatorEntity> query = customerOperatorRepository.getMapper().createLambdaQuery();
        if (Validator.isMobile(operatorLoginName)) {
            query.andEq(CustomerOperatorEntity::getMobile, operatorLoginName);
        } else if (Validator.isEmail(operatorLoginName)) {
            query.andEq(CustomerOperatorEntity::getEmail, operatorLoginName);
        } else {
            throw new IllegalArgumentException("登录名只支持手机号或邮箱");
        }
        CustomerOperatorEntity customerOperatorEntity = query.single();

        if (ObjectUtil.isNull(customerOperatorEntity)) {
            return null;
        }

        return active(customerOperatorEntity.getCustomerId());
    }

    public void login(Customer customer) {
        CustomerLogEntity      customerLogEntity      = customerLogRepository.getMapper().findByCustomerIdAndTypeLast(customer.getCustomerId(), CustomerLogType.LoginSuccess);
        CustomerOperatorEntity customerOperatorEntity = CustomerConverter.convertCustomerOperator(customer.getMasterOperator());
        customerOperatorEntity.setCustomerId(customer.getCustomerId());
        customerOperatorEntity.setLastLoginTime(Optional.ofNullable(customerLogEntity).map(AbstractCreateTimeEntity::getCreateTime).orElse(new Date()));
        customerOperatorEntity.setLastLoginIp(Context.current().realIp());
        customerOperatorRepository.saveOrUpdate(customerOperatorEntity);
    }

    private CustomerFeeRule findCustomerFeeRule(Customer customer) {
        CustomerFeeRule customerFeeRule = CustomerFeeRule.builder().receiptRules(Lists.newArrayList()).transferRules(Lists.newArrayList()).withdrawRules(Lists.newArrayList()).build();
        Account         account         = customer.getAccount();

        return customerFeeRule;
    }

    private Account activeAccount(String customerId) {
        return accountRepository.active(customerId);
    }

    public List<CustomerEntity> listByCustomerId(List<String> customerIds) {
        return getMapper().createLambdaQuery()
                .andIn(CustomerEntity::getCustomerId, Query.filterNull(customerIds))
                .select();
    }

    public List<Customer> simpleWechatActive(List<String> customerIds) {
        if (CollUtil.isEmpty(customerIds)) {
            return null;
        }
        List<CustomerEntity>     entities     = getMapper().listByCustomerIds(customerIds);
        List<CustomerTechEntity> techEntities = getCustomerTechRepository().getMapper().listByCustomerIds(customerIds);

        Map<String, CustomerTechEntity> techEntityMap = techEntities.stream().collect(Collectors.toMap(CustomerTechEntity::getCustomerId, entity -> entity));

        return entities.stream().map(entity -> CustomerConverter.simpleWechatConvert(entity, techEntityMap.get(entity.getCustomerId()))).collect(Collectors.toList());
    }

    public Customer simpleWechatActive(String customerId) {
        CustomerEntity     entity     = getMapper().findByCustomerId(customerId);
        CustomerTechEntity techEntity = getCustomerTechRepository().getMapper().findByCustomerId(customerId);
        return CustomerConverter.simpleWechatConvert(entity, techEntity);
    }

    public CustomerEntity findByCustomerId(String customerId) {
        return getMapper().findByCustomerId(customerId);
    }

    public void deleteByCustomerId(String customerId) {
        getMapper().deleteByCustomerId(customerId);
    }

    public void deleteByMobile(String mobile) {
        getMapper().deleteByMobile(mobile);
    }
}